
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>插件机制 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>插件机制 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">MyBatis 插件机制的主要目的是什么？它能帮助开发者实现哪些功能？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">MyBatis 插件机制允许开发者在 SQL 执行过程中插入自定义行为，从而实现对执行过程的增强和扩展，而无需修改 MyBatis 的核心代码。通过这种机制，可以实现日志记录、性能监控、权限控制等功能。</div>
          </div>
          <div class="card-source">来源: 文档开篇第一段</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">MyBatis 插件机制是基于哪些 Java 技术实现的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">MyBatis 的插件机制基于 Java 的反射和代理技术。它允许开发者对特定接口进行拦截，并在执行前后添加自定义行为。</div>
          </div>
          <div class="card-source">来源: 1. 插件机制的基础</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">实现 MyBatis 插件需要实现 `Interceptor` 接口，请问该接口包含哪三个核心方法，它们各自的作用是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Interceptor 接口包含三个核心方法：`intercept()` 用于拦截并执行自定义逻辑；`plugin()` 用于为目标对象创建代理对象；`setProperties()` 用于在初始化插件时设置相关属性。</div>
          </div>
          <div class="card-source">来源: 1. 插件机制的基础</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">如何在 MyBatis 的配置文件中注册一个自定义插件，并为其传递参数？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">在 `mybatis-config.xml` 配置文件中，使用 `<plugins>` 标签包裹一个或多个 `<plugin>` 标签来注册插件。`<plugin>` 标签的 `interceptor` 属性指定插件的完整类名，其内部可以通过 `<property>` 标签为插件设置参数。</div>
          </div>
          <div class="card-source">来源: 2. 插件注册机制</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">请简述 MyBatis 插件拦截目标方法的五个核心步骤。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">1. MyBatis 创建目标对象（如 Executor）。 2. 插件通过 `plugin()` 方法为目标对象生成代理。 3. 当目标方法被调用时，代理对象会调用 `intercept()` 方法。 4. 插件在 `intercept()` 方法中执行自定义逻辑，并通过 `Invocation.proceed()` 调用原始方法。 5. 插件可以在目标方法执行前后修改参数或返回值，并将最终结果返回。</div>
          </div>
          <div class="card-source">来源: 5. 插件拦截流程</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">在插件的 `intercept` 方法中，`Invocation` 对象扮演什么角色？它提供了哪些关键信息和功能？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Invocation 对象封装了目标方法的调用信息。通过它，插件可以获取目标对象 (target)、目标方法 (method) 以及方法的参数 (args)。同时，它提供了 `proceed()` 方法，用于执行原始的目标方法调用。</div>
          </div>
          <div class="card-source">来源: 4. Invocation对象的使用</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">MyBatis 中的哪些核心组件支持被插件拦截？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">MyBatis 的核心组件如 `Executor`、`StatementHandler`、`ResultSetHandler` 等都支持插件的拦截。</div>
          </div>
          <div class="card-source">来源: 7. 插件与MyBatis核心组件的集成</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">当配置了多个插件时，MyBatis 是如何处理和执行它们的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">MyBatis 支持多个插件，它们会以链式调用的方式执行。每个插件都会依次拦截目标对象的执行，形成一个插件链，可以在目标方法执行前后添加自定义逻辑。</div>
          </div>
          <div class="card-source">来源: 6. 插件链与多个插件的支持</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在开发 MyBatis 插件时，有哪些性能方面的最佳实践？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">为了保证性能，插件开发有三条最佳实践：1. 避免在插件中执行过于复杂的逻辑；2. 尽量减少插件链的长度，避免不必要的插件；3. 合理使用缓存以减少重复操作。</div>
          </div>
          <div class="card-source">来源: 8. 插件的性能与最佳实践</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
